package com.ethink.warehouse.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.db.PageUtils;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.framework.common.web.context.SPRequestContextHolder;
import com.ethink.id.generator.IdGenerator;
import com.ethink.warehouse.api.enums.MateInventoryAdjustLogOrderStatusEnum;
import com.ethink.warehouse.api.info.MateInventoryAdjustLogDetailInfo;
import com.ethink.warehouse.api.info.MateInventoryAdjustLogInfo;
import com.ethink.warehouse.api.info.MateInventoryAdjustLogModeInfo;
import com.ethink.warehouse.api.info.MateInventoryDetailInfo;
import com.ethink.warehouse.api.request.*;
import com.ethink.warehouse.api.response.MateInventoryAdjustLogAddResponse;
import com.ethink.warehouse.api.response.MateInventoryAdjustLogDeleteResponse;
import com.ethink.warehouse.api.response.MateInventoryAdjustLogGetDetailResponse;
import com.ethink.warehouse.api.response.MateInventoryAdjustLogUpdateResponse;
import com.ethink.warehouse.common.entity.MateInventoryAdjustLog;
import com.ethink.warehouse.common.entity.MateInventoryAdjustLogDetail;
import com.ethink.warehouse.common.entity.MatePurchaseCode;
import com.ethink.warehouse.common.entity.SubWarehouse;
import com.ethink.warehouse.common.mapper.*;
import com.ethink.warehouse.converter.MateInventoryAdjustLogConverter;
import com.ethink.warehouse.converter.MateInventoryAdjustLogDetailConverter;
import com.ethink.warehouse.service.MateInventoryAdjustLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 库存矫正记录 Service接口实现
 *
 * @author default
 * @date 2022-11-17
 */
@Slf4j
@Service
public class MateInventoryAdjustLogServiceImpl implements MateInventoryAdjustLogService {

    @Autowired
    private MateInventoryAdjustLogMapper mateInventoryAdjustLogMapper;

    @Autowired
    private MateInventoryAdjustLogConverter mateInventoryAdjustLogConverter;

    @Autowired
    private MateInventoryAdjustLogDetailMapper mateInventoryAdjustLogDetailMapper;

    @Autowired
    private MateInventoryAdjustLogDetailConverter mateInventoryAdjustLogDetailConverter;

    @Autowired
    private MateInventoryAdjustLogDetailService mateInventoryAdjustLogDetailService;

    @Autowired
    private SubWarehouseMapper subWarehouseMapper;

    @Autowired
    private MatePurchaseCodeMapper matePurchaseCodeMapper;

    @Autowired
    private MateInventoryMapper mateInventoryMapper;

    @Autowired
    private IdGenerator idGenerator;

    @Override
    public Page<MateInventoryAdjustLogInfo> queryMateInventoryAdjustLog(MateInventoryAdjustLogQueryRequest request) {
        return mateInventoryAdjustLogMapper.queryMateInventoryAdjustLog(PageUtils.buildPage(request), request);
    }

    @Override
    public MateInventoryAdjustLogGetDetailResponse getMateInventoryAdjustLogById(Long mateInventoryAdjustLogId) {
        MateInventoryAdjustLogInfo mateInventoryAdjustLogInfo = mateInventoryAdjustLogMapper.getMateInventoryAdjustLogById(mateInventoryAdjustLogId);
        List<MateInventoryAdjustLogDetailInfo> mateInventoryAdjustLogDetails =
                mateInventoryAdjustLogDetailMapper.selectByOrderNo(mateInventoryAdjustLogInfo.getOrderNo());
        MateInventoryAdjustLogGetDetailResponse response = new MateInventoryAdjustLogGetDetailResponse();
        response.setMateInventoryAdjustLogInfo(mateInventoryAdjustLogInfo);
        response.setMateInventoryAdjustLogDetailInfoList(mateInventoryAdjustLogDetails);
        return response;
    }

    @Override
    public MateInventoryAdjustLogAddResponse addMateInventoryAdjustLog(MateInventoryAdjustLogAddRequest request) {
        SubWarehouse subWarehouse = subWarehouseMapper.selectOne(
                new LambdaQueryWrapper<SubWarehouse>()
                        .eq(SubWarehouse::getSubWarehouseCode, request.getSubWarehouseCode())
                        .eq(SubWarehouse::getIsDeleted, false));
        MateInventoryAdjustLog mateInventoryAdjustLog = new MateInventoryAdjustLog();
        BeanUtils.copyProperties(request, mateInventoryAdjustLog);
        mateInventoryAdjustLog.setOrderNo(idGenerator.jz());
        mateInventoryAdjustLog.setSubWarehouseName(subWarehouse.getSubWarehouseName());
        List<MateInventoryAdjustLogDetail> detailList = build(request.getItems(), mateInventoryAdjustLog);
        mateInventoryAdjustLogMapper.insert(mateInventoryAdjustLog);
        mateInventoryAdjustLogDetailService.saveBatch(detailList);
        MateInventoryAdjustLogAddResponse response = new MateInventoryAdjustLogAddResponse();
        response.setId(mateInventoryAdjustLog.getId());
        return response;
    }

    private List<MateInventoryAdjustLogDetail> build(List<MateInventoryAdjustLogDetailAddRequest> items, MateInventoryAdjustLog main) {
        List<MateInventoryAdjustLogDetail> detailList = new ArrayList<>();
        Set<Long> mateInventoryIdSet = new HashSet<>();
        mateInventoryIdSet.addAll(items.stream()
                .map(MateInventoryAdjustLogDetailAddRequest::getBeforeMateInventoryId)
                .collect(Collectors.toList()));
        List<MateInventoryDetailInfo> mateInventoryList = mateInventoryMapper.listMateInventoryByIdList(
                mateInventoryIdSet.stream().collect(Collectors.toList()));
        Map<Long, MateInventoryDetailInfo> mateInventoryMap = mateInventoryList.stream().collect(Collectors.toMap(
                MateInventoryDetailInfo::getId, entity -> entity));
        int totalQuantity = 0;
        BigDecimal totalCost = new BigDecimal(0);
        for (MateInventoryAdjustLogDetailAddRequest item : items) {
            MateInventoryDetailInfo beforeMateInventory = mateInventoryMap.get(item.getBeforeMateInventoryId());
            MatePurchaseCode matePurchaseCode = matePurchaseCodeMapper.selectOne(
                    new LambdaQueryWrapper<MatePurchaseCode>()
                            .eq(MatePurchaseCode::getMateSku, beforeMateInventory.getMateSku())
                            .eq(MatePurchaseCode::getPurchaseCode, item.getMatchPurchaseCode())
            );
            if (beforeMateInventory.getAvailableQty() < item.getAdjustQty()) {
                throw new BusinessException(CommonRespCode.SYSTEM_ERR, "调整的库存数量超过可用库存");
            }
            MateInventoryAdjustLogDetail detail = new MateInventoryAdjustLogDetail();
            detail.setOrderNo(main.getOrderNo());
            detail.setBeforeMateInventoryId(item.getBeforeMateInventoryId());
            detail.setMatchPurchaseCode(item.getMatchPurchaseCode());
            detail.setAdjustQty(item.getAdjustQty());
            detail.setAdjustProduceCode(matePurchaseCode.getProduceCode());
            detail.setAdjustCostPrice(beforeMateInventory.getCostPrice());
            detail.setAdjustPurchaseOrderNo(matePurchaseCode.getPurchaseOrderNo());
            detail.setAdjustPurchaseDetailOrderNo(matePurchaseCode.getPurchaseDetailOrderNo());
            detail.setAdjustCountryOfOrigin(matePurchaseCode.getCountryOfOrigin());
            detail.setAdjustProductDate(matePurchaseCode.getProductDate());
            detail.setAdjustExpireDate(matePurchaseCode.getExpireDate());
            detail.setAdjustRkTime(Date.from(matePurchaseCode.getCreateTime().atZone(ZoneId.of("GMT+8")).toInstant()));
            detailList.add(detail);
            totalQuantity += item.getAdjustQty();
            totalCost = totalCost.add(detail.getAdjustCostPrice().multiply(new BigDecimal(detail.getAdjustQty())));
        }
        main.setTotalQuantity(totalQuantity);
        main.setTotalCost(totalCost);
        return detailList;
    }

    @Override
    public MateInventoryAdjustLogUpdateResponse updateMateInventoryAdjustLog(MateInventoryAdjustLogUpdateRequest request) {
        MateInventoryAdjustLogUpdateResponse response = new MateInventoryAdjustLogUpdateResponse();
        MateInventoryAdjustLog main = mateInventoryAdjustLogMapper.selectById(request.getId());
        if (!MateInventoryAdjustLogOrderStatusEnum.S1.eq(main.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前订单状态无法编辑");
        }
        SubWarehouse subWarehouse = subWarehouseMapper.selectOne(
                new LambdaQueryWrapper<SubWarehouse>()
                        .eq(SubWarehouse::getSubWarehouseCode, request.getSubWarehouseCode())
                        .eq(SubWarehouse::getIsDeleted, false));
        List<MateInventoryAdjustLogDetail> detailList = build(request.getItems(), main);
        LambdaUpdateWrapper<MateInventoryAdjustLog> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MateInventoryAdjustLog::getId, request.getId());
        updateWrapper.set(MateInventoryAdjustLog::getOrderStatus, request.getOrderStatus());
        updateWrapper.set(MateInventoryAdjustLog::getSubWarehouseCode, request.getSubWarehouseCode());
        updateWrapper.set(MateInventoryAdjustLog::getAdjustType, request.getAdjustType());
        updateWrapper.set(MateInventoryAdjustLog::getAdjustReason, request.getAdjustReason());
        updateWrapper.set(MateInventoryAdjustLog::getRemark, request.getRemark());
        updateWrapper.set(MateInventoryAdjustLog::getSubWarehouseName, subWarehouse.getSubWarehouseName());
        updateWrapper.set(MateInventoryAdjustLog::getTotalCost, main.getTotalCost());
        updateWrapper.set(MateInventoryAdjustLog::getTotalQuantity, main.getTotalQuantity());
        mateInventoryAdjustLogMapper.update(null, updateWrapper);
        mateInventoryAdjustLogDetailMapper.delete(new LambdaQueryWrapper<MateInventoryAdjustLogDetail>()
                .eq(MateInventoryAdjustLogDetail::getOrderNo, main.getOrderNo())
        );
        mateInventoryAdjustLogDetailService.saveBatch(detailList);
        response.setId(main.getId());
        return response;
    }

    @Override
    public MateInventoryAdjustLogDeleteResponse deleteMateInventoryAdjustLog(Long id) {
        MateInventoryAdjustLogDeleteResponse response = new MateInventoryAdjustLogDeleteResponse();
        MateInventoryAdjustLog main = mateInventoryAdjustLogMapper.selectById(id);
        LambdaUpdateWrapper<MateInventoryAdjustLog> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MateInventoryAdjustLog::getId, id);
        updateWrapper.set(MateInventoryAdjustLog::getIsDeleted, true);
        mateInventoryAdjustLogMapper.update(null, updateWrapper);
        mateInventoryAdjustLogDetailMapper.update(null,
                new LambdaUpdateWrapper<MateInventoryAdjustLogDetail>()
                        .eq(MateInventoryAdjustLogDetail::getOrderNo, main.getOrderNo())
                        .set(MateInventoryAdjustLogDetail::getIsDeleted, true)
        );
        response.setId(main.getId());
        return response;
    }

    @Override
    public void setOrderStatus(Long id, Integer orderStatus) {
        LambdaUpdateWrapper<MateInventoryAdjustLog> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MateInventoryAdjustLog::getId, id);
        updateWrapper.set(MateInventoryAdjustLog::getOrderStatus, orderStatus)
                .set(MateInventoryAdjustLog::getAuditUserCode, SPRequestContextHolder.getCurrentSystemUserLoginName())
                .set(MateInventoryAdjustLog::getAuditUserName, SPRequestContextHolder.getCurrentSystemUserRealName());
        mateInventoryAdjustLogMapper.update(null, updateWrapper);
    }

    @Service
    public static class MateInventoryAdjustLogDetailService extends ServiceImpl<MateInventoryAdjustLogDetailMapper, MateInventoryAdjustLogDetail> {

    }

    @Override
    public Page<MateInventoryAdjustLogModeInfo> queryMateInventoryAdjustLogMode(MateInventoryAdjustLogQueryModeRequest request) {
        return mateInventoryAdjustLogMapper.queryMateInventoryAdjustLogMode(PageUtils.buildPage(request), request);
    }
}
